/********* request请求类 ********/
import RequestMethod from '@/utils/enum/method'
export interface RequestOptions extends UniNamespace.RequestOptions {
    baseUrl?: string,
    loading?: boolean,
    loadingText?: string,
    loadingMask?: boolean,
    isConcat?: boolean, // 断网重连字节小程序不支持
}
// 公共请求库
export default class Request {
    private options: RequestOptions = {
        baseUrl: 'http://127.0.0.1/',
        url: '',
        method: RequestMethod.GET,
        isConcat: true,
        dataType: 'json',
        timeout: 5000,
        loading: true,
        loadingText: '加载中',
        loadingMask: true,
        responseType: 'text',
        header: {
            'Content-Type': 'application/x-www-form-urlencoded',
        },
    };
    private storeOptions: any = uni.getStorageSync("httpOptions") || undefined;
    private static isShow: boolean = false;

    private static mInstance: Request;

    constructor(options: any = {}) {
        this.options = Object.assign(this.options, options)
    }

    // 单例模式创建
    public static getInstance(options: any = {}): Request {
        if (!Request.mInstance) {
            Request.mInstance = new Request(options);
        }
        return Request.mInstance;
    }

    // 拦截器
    public interceptors = {
        // Function | object
        request: (func: any) => {
            if (func) {
                Request.requestBefore = func
            }
            else {
                Request.requestBefore = (request: any) => request
            }
        },
        // Function | object
        response: (func: any) => {
            if (func) {
                Request.requestAfter = func
            }
            else {
                Request.requestAfter = (response: any) => response
            }
        }
    }
    // @params Function | object
    private static requestBefore = (config: any) => config;
    // Function | object
    private static requestAfter = (response: any) => response;
    // 是否是完整的url路径
    private static isCompleteURL = (url: string) => /(http|https):\/\/([\w.]+\/?)\S*/.test(url);

    // 断网自动重新连接
    private onNetworkChange(options: any) {
        uni.onNetworkStatusChange((res) => {
            if (res.isConnected) {
                // 有网络并且有上次请求的数据则重新请求
                if (options.isConcat && this.storeOptions) {
                    this.request(this.storeOptions);
                    // uni.setStorageSync('httpOptions', undefined)
                    this.storeOptions = undefined;
                }
            } else {
                // 无网络保存当前请求数据
                // uni.setStorageSync('httpOptions', options)
                this.storeOptions = options
            }
        });
    }

    /**
     * 发起网络请求
     * @param options 请求参数
     * @returns Promise
     */
    public request(options: RequestOptions = { url: '' }) {
        options.url = Request.isCompleteURL(options.url) ? options.url : this.options.baseUrl + options.url;
        // 合并请求参数重复则覆盖
        options = Object.assign(this.options, Request.requestBefore(options));
        // 断网重新连接
        // #ifndef MP-TOUTIAO
        this.onNetworkChange(options)
        // #endif
        if (!Request.isShow && options.loading) {
            Request.isShow = true;
            uni.showLoading({
                title: options.loadingText,
                mask: options.loadingMask,
            })
        }
        return new Promise((resolve, reject) => {
            options.success = (res: any) => {
                resolve(Request.requestAfter(res))
            }
            options.fail = (err: any) => {
                reject(Request.requestAfter(err))
            }
            options.complete = () => {
                if (this.options.loading) {
                    uni.hideLoading()
                    Request.isShow = false;
                }
            }
            const http: any = uni || wx;
            http.request(options);
        })
    }

    public get(url: string, data?: any, options: any = {}) {
        options.url = url
        options.data = data
        options.method = RequestMethod.GET
        return this.request(options)
    }

    public post(url: string, data?: any, options: any = {}) {
        options.url = url
        options.data = data
        options.method = RequestMethod.POST
        return this.request(options)
    }
}